﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Windows.ApplicationModel;
using Windows.ApplicationModel.DataTransfer;
using Windows.UI.ApplicationSettings;
using MVAScratchPad.Common;
using MVAScratchPad.Services;
using Windows.UI.Xaml.Navigation;
using MVAScratchPad.Models;
using System.Threading.Tasks;

namespace MVAScratchPad.ViewModels
{
    internal class MainPageViewModel : BaseViewModel
    {
        public MainPageViewModel()
        {
            if (DesignMode.DesignModeEnabled)
                SampleData();

            // register for messages
            MessageBus.Instance.Register<ResetNotesMessage>(this, m => { this.DeleteNotesCommand.Execute(null); });

            // setup charms
            new SettingsService { GetCommandsAction = SettingsCharm };
            new SharingService { OnShareRequested = ShareCharm };
        }

        private void SampleData()
        {
            this._Notes = this.Notes ?? new ObservableCollection<NoteModel>();
            this._AllNotes = this._AllNotes ?? new ObservableCollection<NoteModel>();

            // sample data; LoadData() will do the rest
            this.Notes.Add(new NoteModel() { Title = "Mathematics", Notes = "Mathematics is the abstract study of topics such as quantity (numbers), structure, space, and change. There is a range of views among mathematicians and philosophers as to the exact scope and definition of mathematics.\r\n\r\nMathematicians seek out patterns and use them to formulate new conjectures. Mathematicians resolve the truth or falsity of conjectures by mathematical proof. When mathematical structures are good models of real phenomena, then mathematical reasoning can provide insight or predictions about nature. Through the use of abstraction and logic, mathematics developed from counting, calculation, measurement, and the systematic study of the shapes and motions of physical objects. Practical mathematics has been a human activity for as far back as written records exist.\r\n\r\nThe research required to solve mathematical problems can take years or even centuries of sustained inquiry." });
            this.Notes.Add(new NoteModel() { Title = "Zoology", Notes = "The history of zoology traces the study of the animal kingdom from ancient to modern times. Although the concept of zoology as a single coherent field arose much later, the zoological sciences emerged from natural history reaching back to the works of Aristotle and Galen in the ancient Greco-Roman world.\r\n\r\nThis ancient work was further developed in the Middle Ages by Muslim physicians and scholars such as Albertus Magnus. During the Renaissance and early modern period, zoological thought was revolutionized in Europe by a renewed interest in empiricism and the discovery of many novel organisms. Prominent in this movement were Vesalius and William Harvey, who used experimentation and careful observation in physiology, and naturalists such as Carl Linnaeus and Buffon who began to classify the diversity of life and the fossil record, as well as the development and behavior of organisms.\r\n\r\nMicroscopy revealed the previously unknown world of microorganisms, laying the groundwork for cell theory. The growing importance of natural theology, partly a response to the rise of mechanical philosophy, encouraged the growth of natural history (although it entrenched the argument from design)." });
            this.Notes.Add(new NoteModel() { Title = "Philosophy", Notes = "Philosophy is the study of general and fundamental problems, such as those connected with reality, existence, knowledge, values, reason, mind, and language. Philosophy is distinguished from other ways of addressing such problems by its critical, generally systematic approach and its reliance on rational argument. In more casual speech, by extension, 'philosophy' can refer to 'the most basic beliefs, concepts, and attitudes of an individual or group'.\r\n\r\nThe word 'philosophy' comes from the Ancient Greek φιλοσοφία (philosophia), which literally means 'love of wisdom'. The introduction of the terms 'philosopher' and 'philosophy' has been ascribed to the Greek thinker Pythagoras." });
            this.Notes.Add(new NoteModel() { Title = "Endocrinology", Notes = "Endocrinology (from Greek ἔνδον, endo, 'within'; κρῑνω, krīnō, 'to separate'; and -λογία, -logia) is a branch of biology and medicine dealing with the endocrine system, its diseases, and its specific secretions called hormones, the integration of developmental events proliferation, growth, and differentiation (including histogenesis and organogenesis) and the coordination of metabolism, respiration, excretion, movement, reproduction, and sensory perception depend on chemical cues, substances synthesized and secreted by specialized cells.\r\n\r\nEndocrinology is concerned with study of the biosynthesis, storage, chemistry, biochemical and physiological function of hormones and with the cells of the endocrine glands and tissues that secrete them." });
            this.Notes.Add(new NoteModel() { Title = "Philology", Notes = "Endocrinology (from Greek ἔνδον, endo, 'within'; κρῑνω, krīnō, 'to separate'; and -λογία, -logia) is a branch of biology and medicine dealing with the endocrine system, its diseases, and its specific secretions called hormones, the integration of developmental events proliferation, growth, and differentiation (including histogenesis and organogenesis) and the coordination of metabolism, respiration, excretion, movement, reproduction, and sensory perception depend on chemical cues, substances synthesized and secreted by specialized cells.\r\n\r\nEndocrinology is concerned with study of the biosynthesis, storage, chemistry, biochemical and physiological function of hormones and with the cells of the endocrine glands and tissues that secrete them." });
            this.Notes.Add(new NoteModel() { Title = "Gemology", Notes = "Rudimentary education in gemology for jewelers and gemologists began in the nineteenth century, but the first qualifications were instigated after the National Association of Goldsmiths of Great Britain (NAG) set up a Gemmological Committee for this purpose in 1908. This committee matured into the Gemmological Association of Great Britain (also known as Gem-A), now an educational charity and accredited awarding body with its courses taught worldwide. The first US graduate of Gem-A's Diploma Course, in 1929, was Robert Shipley who later established both the Gemological Institute of America and the American Gem Society. There are now several professional schools and associations of gemologists and certification programs around the world." });
            foreach (var item in Notes)
                this.AllNotes.Add(item);
        }

        ObservableCollection<NoteModel> _AllNotes = new ObservableCollection<NoteModel>();
        public ObservableCollection<NoteModel> AllNotes { get { return _AllNotes; } }

        ObservableCollection<NoteModel> _Notes = new ObservableCollection<NoteModel>();
        public ObservableCollection<NoteModel> Notes { get { return _Notes; } }

        string _QueryText = default(string);
        public string QueryText
        {
            get { return _QueryText; }
            set
            {
                SetProperty(ref _QueryText, value);
                Filter();
            }
        }

        // this is only clled by the QueryText setter
        public void Filter()
        {
            var query = this.QueryText.ToLower();
            if (string.IsNullOrWhiteSpace(query))
            {
                this.Notes.Clear();
                foreach (var item in this.AllNotes)
                    this.Notes.Add(item);
                return;
            }
            var matches = AllNotes.Select(x => new { Note = x, Match = (x.Title.ToLower().Contains(query) || x.Notes.ToLower().Contains(query)) });
            foreach (var item in matches)
            {
                var n = this.Notes.FirstOrDefault(x => x.Key.Equals(item.Note.Key));
                if (item.Match && n == null)
                    this.Notes.Add(item.Note);
                else if (!item.Match && n != null)
                    this.Notes.Remove(n);
            }
        }

        string _NewNoteTitle = default(string);
        public string NewNoteTitle { get { return _NewNoteTitle; } set { SetProperty(ref _NewNoteTitle, value); } }

        public override async Task LoadState(NavigationEventArgs m)
        {
            var notes = await StorageHelper.ReadFileAsync<ObservableCollection<NoteModel>>("MainPageViewModel.Notes");
            if (notes != null)
            {
                this._Notes = new ObservableCollection<NoteModel>(notes);
                this._AllNotes = new ObservableCollection<NoteModel>(notes);
            }
            if (!this.Notes.Any())
                SampleData();
        }

        public override async Task SaveState(NavigationEventArgs m)
        {
            // write properties to page state
            await StorageHelper.WriteFileAsync("MainPageViewModel.Notes", this.Notes);
        }

        private void SettingsCharm(IList<SettingsCommand> l)
        {
            // settings charm
            var c = new SettingsCommand("Notes.Options", "Options", o => new Views.Settings().Show());
            l.Add(c);
        }

        private void ShareCharm(DataPackage d)
        {
            // share charm
            if (Notes == null || Notes.Count == 0)
                return;
            d.Properties.Title = "Sharing Note - " + Notes[0].Title;
            d.SetText(Notes[0].TextFormat());
            d.SetHtmlFormat(Notes[0].HtmlFormat());
        }

        RelayCommand<object> _AddNoteCommand = null;
        public RelayCommand<object> AddNoteCommand
        {
            get
            {
                if (_AddNoteCommand != null)
                    return _AddNoteCommand;
                _AddNoteCommand = new RelayCommand<object>
                (
                    o =>
                    {
                        var note = new NoteModel { Title = NewNoteTitle, Notes = "Welcome" };
                        Notes.Insert(0, note);
                        AllNotes.Add(note);
                        this.NewNoteTitle = string.Empty;
                        RaiseAddNoteCompleted();
                    },
                    () => { return !string.IsNullOrEmpty(this.NewNoteTitle); }
                );
                this.PropertyChanged += (s, e) => _AddNoteCommand.RaiseCanExecuteChanged();
                return _AddNoteCommand;
            }
        }

        #region AddNoteCompleted event

        public class AddNoteCompletedEventArgs : System.EventArgs { }
        public event EventHandler<AddNoteCompletedEventArgs> AddNoteCompleted;
        protected void RaiseAddNoteCompleted()
        {
            if (AddNoteCompleted != null)
                AddNoteCompleted(this, new AddNoteCompletedEventArgs { });
        }

        #endregion

        RelayCommand<NoteModel> _DeleteNoteCommand = null;
        public RelayCommand<NoteModel> DeleteNoteCommand
        {
            get
            {
                if (_DeleteNoteCommand != null)
                    return _DeleteNoteCommand;
                _DeleteNoteCommand = new RelayCommand<NoteModel>
                (
                    o =>
                    {
                        Notes.Remove(o);
                        AllNotes.Remove(o);
                    },
                    () => true
                );
                this.PropertyChanged += (s, e) => _DeleteNoteCommand.RaiseCanExecuteChanged();
                return _DeleteNoteCommand;
            }
        }

        RelayCommand<object> _DeleteNotesCommand = null;
        public RelayCommand<object> DeleteNotesCommand
        {
            get
            {
                if (_DeleteNotesCommand != null)
                    return _DeleteNotesCommand;
                _DeleteNotesCommand = new RelayCommand<object>
                (
                    o =>
                    {
                        Notes.Clear();
                        AllNotes.Clear();
                    },
                    () => { return this.Notes.Any(); }
                );
                this.PropertyChanged += (s, e) => _DeleteNotesCommand.RaiseCanExecuteChanged();
                return _DeleteNotesCommand;
            }
        }
    }
}